package ize.android;

import java.io.File;
import java.io.FilenameFilter;
import java.util.Random;

import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.os.SystemClock;
import android.view.MotionEvent;
import android.view.SurfaceHolder;

public class SlideshowWallpaperThread extends Thread implements OnSharedPreferenceChangeListener {
	private SharedPreferences sharedPrefs;
	private SurfaceHolder surfaceHolder;
	private Context context;
	
	/** State */
    private boolean wait;
    private boolean run;
 
    /** Dimensions */
    private int width;
    private int height;
 
    /** Time tracking */
    private long previousTime;
    private long currentTime;
    
	
	private final Paint mPaint = new Paint();
	private long mStartTime;
	
	private File[] pictures;
	private Integer index = -1;    	    	
	private Bitmap myBitmap;
	
	private SlideStates state = SlideStates.ssNextSlide;
    private int alpha = 0;
    private int maxalpha = 200;
    private boolean shuffle = false;
	
	//settings
	private String picturesfolder = "/sdcard";
	private int slideshowinterval = 7000;

    public enum SlideStates {
    	ssFadeOut, ssNextSlide, ssFadeIn, ssDrawCurrent
    }
    
    public SlideshowWallpaperThread(SharedPreferences sharedPrefs, SurfaceHolder surfaceHolder, Context context) {
    	this.sharedPrefs = sharedPrefs;
    	this.surfaceHolder = surfaceHolder;
    	this.context = context;
    	
    	sharedPrefs.registerOnSharedPreferenceChangeListener(this);
    	
    	mStartTime = SystemClock.elapsedRealtime();
    	

		picturesfolder = sharedPrefs.getString("folderselect", picturesfolder);
	    slideshowinterval = Integer.parseInt(sharedPrefs.getString("duration", "7000"));
	    maxalpha = Integer.parseInt(sharedPrefs.getString("opacity", "200"));
	    shuffle = sharedPrefs.getBoolean("shuffle", false);
	   	getPictures();
	   	
	   	this.wait = true;
	   	
	}
    
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
		picturesfolder = sharedPrefs.getString("folderselect", picturesfolder);
	    slideshowinterval = Integer.parseInt(sharedPrefs.getString("duration", "7000"));
	    maxalpha = Integer.parseInt(sharedPrefs.getString("opacity", "200"));
	    shuffle = sharedPrefs.getBoolean("shuffle", false);
	    getPictures();
	}
    
    private void getPictures()
	{
		FilenameFilter filter = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.endsWith(".jpg")||name.endsWith(".jpeg")||name.endsWith(".png");
            }
        };
        pictures = null;
        pictures = new File(picturesfolder).listFiles(filter);
        index = -1;
        mStartTime = 0;
        
        if (shuffle)
        	shuffle(pictures);
        	
	}
    
    private void shuffle(File[] pictures)
	{
		Random rgen = new Random();  // Random number generator
		
		for (int i=0; i<pictures.length; i++) {
		    int randomPosition = rgen.nextInt(pictures.length-1);
		    File temp = pictures[i];
		    pictures[i] = pictures[randomPosition];
		    pictures[randomPosition] = temp;
		}
	}
    
    /**
     * Pauses the live wallpaper animation
     */
    public void pauseDrawing() {
        this.wait = true;
        synchronized(this) {
            this.notify();
        }
    }
 
    /**
     * Resume the live wallpaper animation
     */
    public void resumeDrawing() {
        this.wait = false;
        synchronized(this) {
            this.notify();
        }
    }
 
    /**
     * Stop the live wallpaper animation
     */
    public void stopDrawing() {
        this.run = false;
        synchronized(this) {
            this.notify();
        }
    }
    
    @Override
    public void run() {
        this.run = true;
        Canvas c = null;
        while (run) {
            try {
                c = this.surfaceHolder.lockCanvas(null);
                synchronized (this.surfaceHolder) {                	
                    currentTime = System.currentTimeMillis();
                	doDraw(c);                                 
                    previousTime = currentTime;                     
                }
            } finally {
                if (c != null) {
                    this.surfaceHolder.unlockCanvasAndPost(c);
                }
            }
            // pause if no need to animate
            synchronized (this) {
                if (wait) {
                    try {
                        wait(slideshowinterval);
                        this.wait = false;
                    } catch (Exception e) {}
                }
            }
        }
    }
    
    /**
     * Invoke when the surface dimension change
     */
    public void setSurfaceSize(int width, int height) {
        this.width = width;
        this.height = height;
        synchronized(this) {
            this.notify();
        }
    }
 
    /**
     * Invoke while the screen is touched
     */
    public void doTouchEvent(MotionEvent event) {
        // handle the event here
        // if there is something to animate
        // then wake up
        this.wait = false;
        synchronized(this) {
            notify();
        }
    }
 
    /**
     * Do the actual drawing stuff
     */
    private void doDraw(Canvas c) {
    	if (pictures.length<=0) 
		{
    		//clear background
    		c.drawColor(0, PorterDuff.Mode.CLEAR);
    		mPaint.setAlpha(255);
    		mPaint.setColor(Color.WHITE);
    		mPaint.setStyle(Paint.Style.FILL);
    		mPaint.setTextSize(30);
			c.drawText("No pictures found.", c.getWidth() /2 -100, c.getHeight() /2-50, mPaint);
			return;
		}
    	
    	
    	long now = SystemClock.elapsedRealtime();
    	
    	if ((now - mStartTime) > slideshowinterval)
    	{                		                
    		mStartTime = SystemClock.elapsedRealtime();                		                		
    		state = SlideStates.ssFadeOut;
        	
    	}
    	   	
    	switch (state)
    	{
    		case ssNextSlide:
    			
    			 
    			index++;
        		if (index>=pictures.length) index = 0;
        		
    			//free bitmap
        		if (myBitmap!=null)
        			myBitmap.recycle();
        		
        		//get next bitmap
            	myBitmap = BitmapFactory.decodeFile(pictures[index].getPath());
            	
            	//start fadeIn
            	mStartTime = SystemClock.elapsedRealtime();
            	alpha = 0;
            	state = SlideStates.ssFadeIn;
            	
    			break;
    		
    		case ssFadeIn:
    			//fade in over 1000 msec to 200
    			alpha = (int) ( ((float) (now - mStartTime ) / 1000) * maxalpha);
    			
    			if (alpha >= maxalpha)
    			{
    				
    				alpha = maxalpha;
    				state = SlideStates.ssDrawCurrent;
    			}
    			break;
    		
    		case ssFadeOut:
    			alpha = maxalpha - (int) ( ((float) (now - mStartTime ) / 1000) * maxalpha);
    			
    			if (alpha <= 0)
    			{
    				
    				alpha = 0;
    				state = SlideStates.ssNextSlide;
    			}
    			break;
    		
    		case ssDrawCurrent:
    			//let the thread sleep for the duration of the slide
    			this.wait = true;
    			
    			break;
    	
    	}
    	
    	if (myBitmap==null) return;
    	
    	try
    	{
	    	int width = myBitmap.getWidth();
	        int height = myBitmap.getHeight();
	        int newWidth = c.getWidth();
	        int newHeight = (int) (((float)height / width ) * newWidth);
	        
	        int overflowHeight = (int) ((float) (c.getHeight() - newHeight) / 2);
	       
	        // calculate the scale - in this case = 0.4f
	        float scaleWidth = ((float) newWidth) / width;
	        float scaleHeight = ((float) newHeight) / height;
	       
	        // createa matrix for the manipulation
	        Matrix matrix = new Matrix();
	        // resize the bit map
	        matrix.postScale(scaleWidth, scaleHeight);
	        
	        
	        matrix.postTranslate(0, overflowHeight);
	        
	        
	        
			
	      //clear background
			c.drawColor(0, PorterDuff.Mode.CLEAR);
			mPaint.setAlpha(alpha);
			
			//drawbitmap
	    	c.drawBitmap(myBitmap, matrix, mPaint);
    	} 
    	catch (Exception ex)
    	{
    	
    		//exception occured, go to next slide
    		alpha = 0;
			state = SlideStates.ssNextSlide;
    	}
    }
 
}
